﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace WebChatApi.Common.Audit
{
    /// <summary>
    /// Class for object comparison based on <see cref="AuditItem"/> class objects.
    /// </summary>
    public class ObjectComparison
    {
        #region Properties

        /// <summary>
        /// Gets or sets the name of the source.
        /// NOTE: This property is commonly used to save database table name
        /// </summary>
        /// <value>
        /// The name of the source.
        /// </value>
        public string SourceName
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the source identity.
        /// NOTE: This property is commonly used to save database id/guid.
        /// </summary>
        /// <value>
        /// The source identity.
        /// </value>
        public string SourceIdentity
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the left changeset id.
        /// </summary>
        /// <value>
        /// The left changeset id.
        /// </value>
        public long LeftChangesetId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the right changeset id.
        /// </summary>
        /// <value>
        /// The right changeset id.
        /// </value>
        public long RightChangesetId
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the field comparison results.
        /// </summary>
        /// <value>
        /// The field comparison results.
        /// </value>
        public Dictionary<string, FieldComparison> FieldComparisons
        {
            get;
            protected set;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectComparison"/> class.
        /// </summary>
        public ObjectComparison()
        {
            this.FieldComparisons = new Dictionary<string, FieldComparison>();
        }

        #endregion

        /// <summary>
        /// Adds the or update field comparison left value.
        /// </summary>
        /// <param name="identity">The identity.</param>
        /// <param name="value">The value.</param>
        public void AddOrUpdateFieldComparisonLeftValue(string identity, string value)
        {
            AddOrUpdateFieldComparisonValue(identity, value, true);
        }

        /// <summary>
        /// Adds the or update field comparison right value.
        /// </summary>
        /// <param name="identity">The identity.</param>
        /// <param name="value">The value.</param>
        public void AddOrUpdateFieldComparisonRightValue(string identity, string value)
        {
            AddOrUpdateFieldComparisonValue(identity, value, false);
        }

        /// <summary>
        /// Loads the audit items.
        /// </summary>
        /// <param name="leftChangesetId">The left changeset id.</param>
        /// <param name="leftAuditItem">The left audit item.</param>
        /// <param name="rightChangesetId">The right changeset id.</param>
        /// <param name="rightAuditItem">The right audit item.</param>
        public void LoadAuditItems(long leftChangesetId, AuditItem leftAuditItem, long rightChangesetId, AuditItem rightAuditItem)
        {
            this.LeftChangesetId = leftChangesetId;
            this.RightChangesetId = rightChangesetId;

            if (leftChangesetId > 0 && leftAuditItem != null && rightChangesetId > 0 && rightAuditItem != null)
            {
                LoadXml(leftAuditItem.DataXml, true);
                LoadXml(leftAuditItem.DataXml, false);
            }
        }

        /// <summary>
        /// Compares the value.
        /// </summary>
        /// <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
        /// <returns></returns>
        public bool CompareValue(bool ignoreCase = true)
        {
            bool result = true;
            foreach (var key in this.FieldComparisons.Keys)
            {
                if (!this.FieldComparisons[key].CompareValue(ignoreCase))
                {
                    result = false;
                    break;
                }
            }
            return result;
        }

        #region Protected methods


        /// <summary>
        /// Adds the or update field comparison value.
        /// </summary>
        /// <param name="identity">The identity.</param>
        /// <param name="value">The value.</param>
        /// <param name="isLeft">if set to <c>true</c> [is left].</param>
        protected void AddOrUpdateFieldComparisonValue(string identity, string value, bool isLeft = true)
        {
            if (!this.FieldComparisons.ContainsKey(identity))
            {
                this.FieldComparisons.Add(identity, new FieldComparison());
            }

            if (isLeft)
            {
                this.FieldComparisons[identity].LeftValue = value;
            }
            else
            {
                this.FieldComparisons[identity].RightValue = value;
            }
        }

        /// <summary>
        /// Loads the XML.
        /// </summary>
        /// <param name="dataXml">The data XML.</param>
        /// <param name="isLeft">if set to <c>true</c> [is left].</param>
        protected void LoadXml(XElement dataXml, bool isLeft = true)
        {
            if (dataXml != null && dataXml.HasElements)
            {
                foreach (var one in dataXml.Elements())
                {
                    if (!one.HasElements)
                    {
                        AddOrUpdateFieldComparisonValue(one.Name.LocalName, one.Value, isLeft);
                    }
                }
            }
        }

        #endregion
    }
}
